
float2 sampleOffsets[16];
float4 sampleWeights[16];

static const float  MIDDLE_GRAY = 0.72f;
static const float  LUM_WHITE = 1.5f;
static const float  BRIGHT_THRESHOLD = 0.5f;
static const float LUM = 0.5f;

texture sourceTexture = NULL;
texture bloomTexture = NULL;

sampler samplerSourceImage = 
sampler_state
{
	Texture = <sourceTexture>;
	MinFilter = Point;
	MagFilter = Point;
};

sampler samplerBloomImage = 
sampler_state
{
	Texture = <bloomTexture>;
	MinFilter = Linear;
	MagFilter = Linear;
};


float4 PS_DownScale3X3_BrightPass(in float2 vScreenPosition : TEXCOORD0) : COLOR
{
	float3 vColor = 0.0f;

	for (int i = 0; i < 9; i++)
	{
		// Compute the sum of color values
		float4 vSample = tex2D(samplerSourceImage, vScreenPosition + sampleOffsets[i] );
		vColor += vSample.rgb;
	}

	// Divide the sum to complete the average
	vColor /= 9;

	// Bright pass and tone mapping
	vColor = max(0.0f, vColor - BRIGHT_THRESHOLD);
	vColor *= MIDDLE_GRAY / (LUM + 0.001f);
	vColor *= (1.0f + vColor / LUM_WHITE);
	vColor /= (1.0f + vColor);

	return float4(vColor, 1.0f);
}

float4 PS_Bloom(in float2 vScreenPosition : TEXCOORD0) : COLOR
{
	float4 vSample = 0.0f;
	float4 vColor = 0.0f;

	for (int iSample = 0; iSample < 15; iSample++)
	{
		// Sample from adjacent points
		vColor = tex2D(samplerSourceImage, vScreenPosition + sampleOffsets[iSample]);

		vSample += sampleWeights[iSample] * vColor;
	}

	return vSample;
}

float4 PS_FinalPass(in float2 vScreenPosition : TEXCOORD0) : COLOR
{
	float4 vColor = tex2D(samplerSourceImage, vScreenPosition);
	float3 vBloom = tex2D(samplerBloomImage, vScreenPosition);

	// Tone mapping
	vColor.rgb *= MIDDLE_GRAY / (LUM + 0.001f);
	vColor.rgb *= (1.0f + vColor / LUM_WHITE);
	vColor.rgb /= (1.0f + vColor);
	vColor.rgb += 0.6f * vBloom;
	vColor.a = 1.0f;

	return vColor;
}

technique DownScale3X3_BrightPass
{
	pass p0
	{
		ZEnable = False;
		CullMode = None;
		PixelShader = compile ps_2_0 PS_DownScale3X3_BrightPass();
	}
}

technique Bloom
{
	pass p0
	{
		ZEnable = False;
		CullMode = None;
		PixelShader = compile ps_2_0 PS_Bloom();
	}
}

technique FinalPass
{
	pass p0
	{
		ZEnable = False;
		CullMode = None;
		PixelShader = compile ps_2_0 PS_FinalPass();
	}
}